#include "stdafx.h"
#include "EditObjectTwBar.h"

#include "Node.h"
#include "Scene.h"
#include "MyMath.h"
#include "GfxObject.h"
#include "Light.h"
#include "MultiObjectNode.h"

#include "MeshInstance.h"
#include "Material.h"
#include "ModelNode.h"

using namespace medit;

TwBar * bar = NULL;
mscene::Node * _Node = NULL;
mscene::Scene * _Scene;
bool nodeRemoved = false;


void TW_CALL objectFloatGet(void *value, void *clientData)
{
	*(float*)value = *(float*)clientData;
}

void TW_CALL objectFloatSet(const void *value, void *clientData)
{
	*(float*)clientData = *(float*)value;
	_Node->commitEditorChanges();
}

void TW_CALL isStaticGet(void *value, void *clientData)
{
	*(bool*)value = _Node->IsStatic;
}

void TW_CALL isStaticSet(const void *value, void *clientData)
{
	_Node->IsStatic = *(bool*)value;
	_Node->commitEditorChanges();
}

void TW_CALL orientationSet(const void *value, void *clientData)
{
	//XMFLOAT3 direction = *(XMFLOAT3*)value;
	//XMVECTOR orientation = XMQuaternionRotationRollPitchYaw(
	//	(direction.x),
	//	(direction.y),
	//	(direction.z));
	//XMStoreFloat4(&_Node->Orientation, orientation);

	_Node->Orientation = *(XMFLOAT4*)value;
	_Node->commitEditorChanges();
}

void TW_CALL orientationGet(void *value, void *clientData)
{
	//XMFLOAT3 & direction = *(XMFLOAT3*)value;

	//XMVECTOR eulerAngles = mmath::quaternionToEulerAngles(XMLoadFloat4(&_Node->Orientation));
	//direction.x = (XMVectorGetX(eulerAngles));
	//direction.y = (XMVectorGetY(eulerAngles));
	//direction.z = (XMVectorGetZ(eulerAngles));

	*(XMFLOAT4*)value = _Node->Orientation;
}

void TW_CALL copyObject(void *clientData)
{
	_Scene->addNode(*_Node->copy());
}

void TW_CALL deleteObject(void *clientData)
{
	_Scene->deleteNode(*_Node);
	nodeRemoved = true;
	//editObjectHideBar();
}

static void addPointLightVars(mgfx::PointLight & light)
{
	TwAddVarRW(bar, "Color", TW_TYPE_COLOR3F, &light.Color, "group=PointLight");
	TwAddVarRW(bar, "Intensity", TW_TYPE_FLOAT, &light.Intensity, "group=PointLight min=0 step=0.01");
	TwAddVarRW(bar, "Radius", TW_TYPE_FLOAT, &light.Radius, "group=PointLight min=1");
	TwAddVarRW(bar, "Falloff", TW_TYPE_FLOAT, &light.Falloff, "group=PointLight min=0 step=0.1");
}

static void addSpotLightVars(mgfx::SpotLight & light)
{
	TwAddVarRW(bar, "Color", TW_TYPE_COLOR3F, &light.Color, "group=SpotLight");
	TwAddVarRW(bar, "Intensity", TW_TYPE_FLOAT, &light.Intensity, "group=SpotLight min=0 step=0.01");
	TwAddVarRW(bar, "Radius", TW_TYPE_FLOAT, &light.Radius, "group=SpotLight min=1");
	TwAddVarRW(bar, "Falloff", TW_TYPE_FLOAT, &light.Falloff, "group=SpotLight min=0 step=0.1");
	TwAddVarRW(bar, "SpotFalloff", TW_TYPE_FLOAT, &light.SpotFalloff, "group=SpotLight min=0 step=0.1");
	TwAddVarRW(bar, "SpotAngle", TW_TYPE_FLOAT, &light.SpotAngleRad, "group=SpotLight min=0.01 step=0.01");
	TwAddVarRW(bar, "CastShadows", TW_TYPE_BOOLCPP, &light.IsCastingShadows, "group=SpotLight");
}

static void addMeshInstanceVars(mgfx::MeshInstance & meshInstance)
{
	TwAddVarRW(bar, "Diffuse color", TW_TYPE_COLOR3F, &meshInstance.Material_->DiffuseColor, "group=Model");
}

static void addComponentVars()
{
	if(_Node->Type == mscene::Node::MULTIOBJECT)
	{
		mscene::MultiObjectNode & multiNode = *(mscene::MultiObjectNode*)_Node;
		for(uint i = 0; i < multiNode.GfxObjects.size(); i++)
		{
			mgfx::GfxObject & gfxObj = *multiNode.GfxObjects[i];

			if(gfxObj.Type == mgfx::GfxObject::POINT_LIGHT)
			{
				addPointLightVars((mgfx::PointLight &)gfxObj);
			}

			if(gfxObj.Type == mgfx::GfxObject::SPOT_LIGHT)
			{
				addSpotLightVars((mgfx::SpotLight &)gfxObj);
			}

			if(gfxObj.Type == mgfx::GfxObject::MESH_INSTANCE)
			{
				addMeshInstanceVars((mgfx::MeshInstance &)gfxObj);
			}
		}
	}
	else if (_Node->Type == mscene::Node::MODEL)
	{
		mscene::ModelNode & modelNode = *(mscene::ModelNode*)_Node;
		addMeshInstanceVars(modelNode.getModelEditable());
	}
}

void medit::showEditObjectBar(mscene::Scene & scene, const mscene::Camera & camera, mscene::Node & node)
{
	_Node = &node;
	_Scene = &scene;

	nodeRemoved = false;

	if(bar == NULL)
		bar = TwNewBar("Edit object");
	TwSetTopBar(bar);

	TwRemoveAllVars(bar);

	TwAddVarRW(bar, "Name", TW_TYPE_CSSTRING(mscene::Node::NAME_MAX_SIZE), node.mName, "");

	TwAddVarCB(bar, "Pos X", TW_TYPE_FLOAT, objectFloatSet, objectFloatGet, &node.Position.x, "");
	TwAddVarCB(bar, "Pos Y", TW_TYPE_FLOAT, objectFloatSet, objectFloatGet, &node.Position.y, "");
	TwAddVarCB(bar, "Pos Z", TW_TYPE_FLOAT, objectFloatSet, objectFloatGet, &node.Position.z, "");

	//TwAddVarRW(bar, "Pos X", TW_TYPE_FLOAT, &node.Position.x, "");
	//TwAddVarRW(bar, "Pos Y", TW_TYPE_FLOAT, &node.Position.y, "");
	//TwAddVarRW(bar, "Pos Z", TW_TYPE_FLOAT, &node.Position.z, "");

	TwAddVarCB(bar, "Orientation", TW_TYPE_QUAT4F, orientationSet, orientationGet, NULL, "");

	TwAddVarCB(bar, "Scale X", TW_TYPE_FLOAT, objectFloatSet, objectFloatGet, &node.Scale.x, "min=0.01 step=0.01");
	TwAddVarCB(bar, "Scale Y", TW_TYPE_FLOAT, objectFloatSet, objectFloatGet, &node.Scale.y, "min=0.01 step=0.01");
	TwAddVarCB(bar, "Scale Z", TW_TYPE_FLOAT, objectFloatSet, objectFloatGet, &node.Scale.z, "min=0.01 step=0.01");

	//TwAddVarRW(bar, "Scale X", TW_TYPE_FLOAT, &node.Scale.x, "min=0 step=0.01");
	//TwAddVarRW(bar, "Scale Y", TW_TYPE_FLOAT, &node.Scale.y, "min=0 step=0.01");
	//TwAddVarRW(bar, "Scale Z", TW_TYPE_FLOAT, &node.Scale.z, "min=0 step=0.01");

	TwAddVarCB(bar, "Static", TW_TYPE_BOOLCPP, isStaticSet, isStaticGet, &node.IsStatic, "");
	//TwAddVarRW(bar, "Static", TW_TYPE_BOOLCPP, &node.IsStatic, "");

	TwAddButton(bar, "Copy object", copyObject, NULL, "");
	TwAddButton(bar, "Delete object", deleteObject, NULL, "");

	addComponentVars();
}

void medit::hideEditObjectBar()
{
	if(bar != NULL)
		TwDeleteBar(bar);
	bar = NULL;
}

bool medit::editObjectIsRemoved()
{
	return nodeRemoved;
}